#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "mp4.h"

int __read_32(int fd, u_int32_t *i)
{
	if (read(fd, i, 4) != 4)
		return 0;
	ntohl(*i);
	return 1;
};
int __read_8(int fd, unsigned char *c)
{
	if (read(fd, c, 1) != 1)
		return 0;
	return 1;
};
int __read_24(int fd, unsigned int *i)
{
	if (read(fd, i, 3) != 3)
		return 0;
	return 1;
};

int __read_64(int fd, u_int64_t *i)
{
	if (!__read_32(fd, (u_int32_t*)i))
		return 0;
	*i <<= 32;
	return __read_32(fd, (u_int32_t*)i);
};

int __write_32(int fd, u_int32_t i)
{
	i = htonl(i);
	if (send(fd, &i, 4, 0) != 4)
		return 0;
	return 1;
};
int __write_8(int fd, unsigned char c)
{
	if (send(fd, &c, 1, 0) != 1)
		return 0;
	return 1;
};
int __write_24(int fd, unsigned int i)
{
	if (send(fd, &i, 3, 0) != 3)
		return 0;
	return 1;
};

int __write_64(int fd, u_int64_t i)
{
	u_int64_t _i = i >> 32;
	if (!__write_32(fd, (u_int32_t)_i))
		return 0;
	return __write_32(fd, (u_int32_t)i);
};
int __skip(int fd, int am)
{
	return lseek(fd, am, SEEK_CUR);
}
int __seek(int fd, int am) 
{
	return lseek(fd, am, SEEK_SET);
}

#define read_32(fd, i) if (!__read_32(fd, i)) return 0;
#define read_8(fd, c) if (!__read_8(fd, c)) return 0;
#define read_24(fd, i) if (!__read_24(fd, i)) return 0;
#define read_64(fd, i) if (!__read_64(fd, i)) return 0;
#define skip(fd, am) if (!__skip(fd, am)) return 0;
#define seek(fd, am) if (!__seek(fd, am)) return 0;
#define send_32(fd, i) if (!__write_32(fd, i)) return 0;
#define send_8(fd, c) if (!__write_8(fd, c)) return 0;
#define send_24(fd, i) if (!__write_24(fd, i)) return 0;
#define send_64(fd, i) if (!__write_64(fd, i)) return 0;
#define MALLOC(e) do {\
	e = malloc(sizeof(typeof(*e)));\
	if (!e) return 0;\
}while (0)

#define read_hdr(fd, offset, hdr, str) do {\
	hdr.offset = offset; \
	seek(fd, offset);\
	read_32(fd, &hdr.size); \
	hdr.type.itype = *(u_int32_t*)str; \
	hdr.type.type[4] = 0;\
	skip(fd, 4);\
}while (0)
#define read_fullhdr(fd, offset, hdr, str) do {\
	hdr.offset = offset; \
	seek(fd, offset);\
	read_32(fd, &hdr.size); \
	hdr.type.itype = *(u_int32_t*)str; \
	hdr.type.type[4] = 0;\
	skip(fd, 4);\
	read_8(fd, &hdr.ver); \
	read_24(fd, &hdr.flags);\
} while (0)
#define send_boxhdr(sock, hdr) do {\
	send_32(sock, hdr.size);\
	send_32(sock, hdr.type.itype);\
} while (0)
#define send_fullboxhdr(sock, hdr) do {\
	send_32(sock, hdr.size);\
	send_32(sock, hdr.type.itype);\
	send_8(sock, hdr.ver);\
	send_24(sock, hdr.flags);\
} while (0)
/* 
 * stts
 */
int stts_read(struct stts *stts, int fd, unsigned int offset)
{
	int i;
	read_fullhdr(fd, offset, stts->hdr, "stts");

	read_32(fd, &stts->count);
	INIT_LIST_HEAD(&stts->entry);	
	for (i=0; i<stts->count; i++) {
		struct stts_entry *e;
		MALLOC(e);
		read_32(fd, &e->count);
		read_32(fd, &e->delta);
		list_add_tail(&e->list, &stts->entry);
	}
	return 1;
}

int stts_send(struct stts *stts, int fd, int sock)
{
	int i;
	struct stts_entry *e = container_of(stts->entry.next, struct stts_entry, list);
	send_fullboxhdr(sock, stts->hdr);
	send_32(sock, stts->count);
	for (i=0; i<stts->count; i++) {
		send_32(sock, e->count);
		send_32(sock, e->delta);
		e = container_of(e->list.next, struct stts_entry, list);
	}
	return 1;
}

/* return length cutted, never fail */
int stts_cut(struct stts *stts, unsigned long long keyframe) 
{
	int lencut = 0;
	struct stts_entry *e;
	unsigned long long i;
	unsigned long long entries = stts->count;
	for (i=0; i<entries; i++) {
		e = container_of(stts->entry.next, struct stts_entry, list);
		if (keyframe <= e->count)
			break;
		keyframe -= e->count;
		list_del(stts->entry.next);
		free(e);
		stts->count --;
		lencut += 8;
	}
	stts->hdr.size -= lencut;
	if (i >= entries)
		return lencut;
	/* we found the entry, modify sample count and delta */
	e->count -= (keyframe - 1);
	return lencut;
}

unsigned long long stts_duration(struct stts *stts)
{
	unsigned long long duration = 0;
	struct stts_entry *e = container_of(stts->entry.next, struct stts_entry, list);
	unsigned long long i;
	unsigned long long entries = stts->count;
	for (i=0; i<entries; i++) {
		duration += e->count * e->delta;
		e = container_of(e->list.next, struct stts_entry, list);
	}
	return duration;
}

void stts_free(struct stts *stts)
{
	struct stts_entry *e;
	unsigned long long i;
	unsigned long long entries = stts->count;
	for (i=0; i<entries; i++) {
		e = container_of(stts->entry.next, struct stts_entry, list);
		list_del(stts->entry.next);
		free(e);
	}
}

unsigned long long stts_time_to_sample(struct stts *stts, unsigned long long time)
{
	int i;
	struct stts_entry *e = container_of(stts->entry.next, struct stts_entry, list);
	unsigned long long samplepass = 0;
	unsigned long long timepass = 0;
	for (i=0; i<stts->count; i++) {
		if (timepass + (e->count * e->delta) > time) {
			return (time - timepass) / e->delta + samplepass;
		}
		timepass += e->count * e->delta;
		samplepass += e->count;
		e = container_of(e->list.next, struct stts_entry, list);
	}
	return 1;
}



/* 
 * ctts
 */
int ctts_read(struct ctts *ctts, int fd, unsigned int offset)
{
	int i;
	read_fullhdr(fd, offset, ctts->hdr, "ctts");

	read_32(fd, &ctts->count);
	INIT_LIST_HEAD(&ctts->entry);	
	for (i=0; i<ctts->count; i++) {
		struct ctts_entry *e;
		MALLOC(e);
		read_32(fd, &e->count);
		read_32(fd, &e->offset);
		list_add_tail(&e->list, &ctts->entry);
	}
	return 1;
}

int ctts_send(struct ctts *ctts, int fd, int sock)
{
	int i;
	struct ctts_entry *e = container_of(ctts->entry.next, struct ctts_entry, list);
	send_fullboxhdr(sock, ctts->hdr);
	send_32(sock, ctts->count);
	for (i=0; i<ctts->count; i++) {
		send_32(sock, e->count);
		send_32(sock, e->offset);
		e = container_of(e->list.next, struct ctts_entry, list);
	}
	return 1;
}

/* return length cutted, never fail */
int ctts_cut(struct ctts *ctts, unsigned long long keyframe) 
{
	int lencut = 0;
	struct ctts_entry *e;
	unsigned long long i;
	unsigned long long entries = ctts->count;
	for (i=0; i<entries; i++) {
		e = container_of(ctts->entry.next, struct ctts_entry, list);
		if (keyframe <= e->count)
			break;
		keyframe -= e->count;
		list_del(ctts->entry.next);
		free(e);
		ctts->count --;
		lencut += 8;
	}
	ctts->hdr.size -= lencut;
	if (i >= entries)
		return lencut;
	/* we found the entry, modify sample count and delta */
	e->count -= (keyframe - 1);
	return lencut;
}

void ctts_free(struct ctts *ctts)
{
	struct ctts_entry *e;
	unsigned long long i;
	unsigned long long entries = ctts->count;
	for (i=0; i<entries; i++) {
		e = container_of(ctts->entry.next, struct ctts_entry, list);
		list_del(ctts->entry.next);
		free(e);
	}
}

/* 
 * stsc
 */
int stsc_read(struct stsc *stsc, int fd, unsigned int offset)
{
	int i;
	read_fullhdr(fd, offset, stsc->hdr, "stsc");
	read_32(fd, &stsc->count); 
	INIT_LIST_HEAD(&stsc->entry);	
	for (i=0; i<stsc->count; i++) {
		struct stsc_entry *e;
		MALLOC(e);
		read_32(fd, &e->first_chunk);
		read_32(fd, &e->sample_per_chunk);
		read_32(fd, &e->sample_desc_index);
		list_add_tail(&e->list, &stsc->entry);
	}
	return 1;
}

int stsc_send(struct stsc *stsc, int fd, int sock)
{
	int i;
	struct stsc_entry *e = container_of(stsc->entry.next, struct stsc_entry, list);
	send_fullboxhdr(sock, stsc->hdr);
	send_32(sock, stsc->count);
	for (i=0; i<stsc->count; i++) {
		send_32(sock, e->first_chunk);
		send_32(sock, e->sample_per_chunk);
		send_32(sock, e->sample_desc_index);
		e = container_of(e->list.next, struct stsc_entry, list);
	}
	return 1;
}

int size_arglly(int fd, struct stsz *stsz, unsigned long long samplefrom, int num)
{
	int i;
	unsigned int sum = 0;
	if (stsz->sample_size)
		return num * stsz->sample_size;
	seek(fd, stsz->hdr.offset + 5 + samplefrom -1);
	for (i=0; i<num; i++) {
		u_int32_t tmp;
		read_32(fd, &tmp);
		sum += tmp;
	}
	return sum;
}
/* 
 * @sisz is used to compute first_chunk_offset_inc
 * @tt_chunk_del is total chunk need to delete, is 
 * an output value. pass in as 0
 */
int stsc_cut(int fd, struct stsc *stsc, unsigned long long keyframe, struct stsz *stsz, unsigned int *first_chunk_offset_inc, unsigned int *tt_chunk_del) 
{
	unsigned long long orig_kerframe = keyframe;
	int lencut = 0;
	struct stsc_entry *e;
	struct stsc_entry *enext;
	unsigned long long i;
	unsigned long long entries = stsc->count;

	unsigned int chunk_del;
	unsigned int am;
	for (i=0; i<entries; i++) {
		int sample_num;
		e = container_of(stsc->entry.next, struct stsc_entry, list);
		if (i + 1 == entries)  /* the last entry */
			break;
		enext = container_of(stsc->entry.next->next, struct stsc_entry, list);
		sample_num = (enext->first_chunk - e->first_chunk) * e->sample_per_chunk;
		if (keyframe <= sample_num)
			break;
		keyframe -= sample_num;
		list_del(&e->list);
		free(e);
		stsc->count --;
		lencut += 12;
		*tt_chunk_del += enext->first_chunk - e->first_chunk;
	}
	chunk_del = (keyframe -1)/e->sample_per_chunk;
	*tt_chunk_del += chunk_del;
	keyframe -= chunk_del * e->sample_per_chunk;
	e->first_chunk += chunk_del;
	if (keyframe != 1) { /* split the entry */
		struct stsc_entry *enew;
		MALLOC(enew);
		{
			/* not good */
			*first_chunk_offset_inc = size_arglly(fd, stsz, orig_kerframe - (keyframe-1), keyframe-1);
		}
		enew->first_chunk = e->first_chunk;
		enew->sample_per_chunk = e->sample_per_chunk - (keyframe - 1);
		enew->sample_desc_index = e->sample_desc_index;
		list_add(&enew->list, &stsc->entry);
		stsc->count ++;
		lencut -= 12;
		e->first_chunk ++;
	}
	/* 
	 * update all entries' first_chunk 
	 * the stsc->count always larger than 0
	 */

	e = container_of(stsc->entry.next, struct stsc_entry, list);
	am = e->first_chunk - 1; 
	for (i=0; i<stsc->count; i++) {
		struct stsc_entry *tmp;
		e->first_chunk -= am;
		tmp = container_of(e->list.next, struct stsc_entry, list);
		e = tmp;
	}
	stsc->hdr.size -= lencut;
	return lencut;
}

void stsc_free(struct stsc *stsc)
{
	struct stsc_entry *e;
	unsigned long long i;
	unsigned long long entries = stsc->count;
	for (i=0; i<entries; i++) {
		e = container_of(stsc->entry.next, struct stsc_entry, list);
		list_del(stsc->entry.next);
		free(e);
	}
}


/* 
 * stsz
 */
int stsz_read(struct stsz *stsz, int fd, unsigned int offset)
{
	int i;
	read_fullhdr(fd, offset, stsz->hdr, "stsz");
	read_32(fd, &stsz->sample_size); 
	read_32(fd, &stsz->sample_count); 
	INIT_LIST_HEAD(&stsz->entry);	
	if (stsz->sample_size)
		return 1;
	for (i=0; i<stsz->sample_count; i++) {
		struct stsz_entry *e;
		MALLOC(e);
		read_32(fd, &e->size);
		list_add_tail(&e->list, &stsz->entry);
	}
	return 1;
}

int stsz_send(struct stsz *stsz, int fd, int sock)
{
	int i;
	struct stsz_entry *e = container_of(stsz->entry.next, struct stsz_entry, list);
	send_fullboxhdr(sock, stsz->hdr);
	send_32(sock, stsz->sample_size);
	send_32(sock, stsz->sample_count);
	if (stsz->sample_size)
		return 1;
	for (i=0; i<stsz->sample_count; i++) {
		send_32(sock, e->size);
		e = container_of(e->list.next, struct stsz_entry, list);
	}
	return 1;
}

/* return length cutted, never fail */
int stsz_cut(struct stsz *stsz, unsigned long long keyframe) 
{
	int lencut = 0;
	struct stsz_entry *e;
	unsigned long long i;
	unsigned long long entries = stsz->sample_count;
	if (stsz->sample_size)
		return lencut;
	for (i=0; i<keyframe-1; i++) {
		e = container_of(stsz->entry.next, struct stsz_entry, list);
		list_del(stsz->entry.next);
		free(e);
		stsz->sample_count --;
		lencut += 4;
	}
	stsz->hdr.size -= lencut;
	return lencut;
}

void stsz_free(struct stsz *stsz)
{
	struct stsz_entry *e;
	unsigned long long i;
	unsigned long long entries = stsz->sample_count;
	if (stsz->sample_size)
		return;
	for (i=0; i<entries; i++) {
		e = container_of(stsz->entry.next, struct stsz_entry, list);
		list_del(stsz->entry.next);
		free(e);
	}
}

/* 
 * stco
 */
int stco_read(struct stco *stco, int fd, unsigned int offset)
{
	int i;
	read_fullhdr(fd, offset, stco->hdr, "stco");
	read_32(fd, &stco->count); 
	INIT_LIST_HEAD(&stco->entry);	
	for (i=0; i<stco->count; i++) {
		struct stco_entry *e;
		MALLOC(e);
		read_32(fd, &e->offset);
		list_add_tail(&e->list, &stco->entry);
	}
	return 1;
}

int stco_send(struct stco *stco, int fd, int sock)
{
	/* >>>>>>>>>>> i stop here <<<<<<<<<<<<<<<*/
	/* 
	 * because i found that there are so many place 
	 * that i pay not attention to it 
	 * i give it up
	 */
//	int i;
//	struct stsz_entry *e = container_of(stsz->entry.next, struct stsz_entry, list);
//	send_fullboxhdr(sock, stsz->hdr);
//	send_32(sock, stsz->sample_size);
//	send_32(sock, stsz->sample_count);
//	if (stsz->sample_size)
//		return 1;
//	for (i=0; i<stsz->sample_count; i++) {
//		send_32(sock, e->size);
//		e = container_of(e->list.next, struct stsz_entry, list);
//	}
	return 1;
}

/* 
 * return length cutted, never fail 
 * @chunk: the chunk number need to be deleted
 */
int stco_cut(struct stco *stco, unsigned int chunk) 
{
	int lencut = 0;
	struct stco_entry *e;
	unsigned long long i;
	unsigned long long entries = stco->count;
	for (i=0; i<chunk; i++) {
		e = container_of(stco->entry.next, struct stco_entry, list);
		list_del(stco->entry.next);
		free(e);
		stco->count --;
		lencut += 4;
	}
	stco->hdr.size -= lencut;
	return lencut;
}

void stco_update_offset(struct stco *stco, unsigned int offset)
{
	int i;
	struct stco_entry *e = container_of(stco->entry.next, struct stco_entry, list);
	for (i=0; i<stco->count; i++) {
		e->offset -= offset;
		e = container_of(e->list.next, struct stco_entry, list);
	}
}

void stco_free(struct stco *stco)
{
	struct stco_entry *e;
	unsigned long long i;
	unsigned long long entries = stco->count;
	for (i=0; i<entries; i++) {
		e = container_of(stco->entry.next, struct stco_entry, list);
		list_del(stco->entry.next);
		free(e);
	}
}


/* 
 * stss
 */
int stss_read(struct stss *stss, int fd, unsigned int offset)
{
	int i;
	read_fullhdr(fd, offset, stss->hdr, "stss");
	read_32(fd, &stss->count); 
	INIT_LIST_HEAD(&stss->entry);	
	for (i=0; i<stss->count; i++) {
		struct stss_entry *e;
		MALLOC(e);
		read_32(fd, &e->sample_num);
		list_add_tail(&e->list, &stss->entry);
	}
	return 1;
}


int stss_cut(struct stss *stss, unsigned int keyframe) 
{
	int lencut = 0;
	struct stss_entry *e;
	unsigned long long i;
	unsigned long long entries = stss->count;
	unsigned int am = keyframe -1;
	for (i=0; i<entries; i++) {
		e = container_of(stss->entry.next, struct stss_entry, list);
		if (e->sample_num < keyframe) {
			list_del(stss->entry.next);
			free(e);
			stss->count --;
			lencut += 4;
			continue;
		}
		break;
	}
	entries = stss->count;
	e = container_of(stss->entry.next, struct stss_entry, list);
	for (i=0; i<entries; i++) {
		struct stss_entry *t;
		e->sample_num -= am;
		t = container_of(e->list.next, struct stss_entry, list);
		e = t;
	}
	stss->hdr.size -= lencut;
	return lencut;
}


void stss_free(struct stss *stss)
{
	struct stss_entry *e;
	unsigned long long i;
	unsigned long long entries = stss->count;
	for (i=0; i<entries; i++) {
		e = container_of(stss->entry.next, struct stss_entry, list);
		list_del(stss->entry.next);
		free(e);
	}
}

unsigned long long stss_get_keyframe(struct stss *stss, unsigned long long sample)
{
	unsigned long long last = 1;
	struct stss_entry *e = container_of(stss->entry.next, struct stss_entry, list);
	unsigned long long i;
	unsigned long long entries = stss->count;
	for (i=0; i<entries; i++) {
		if ( sample < e->sample_num)
			return last;
		last = e->sample_num;
	}
	return 1;
}

/* 
 * stbl
 */
int stbl_read(struct stbl *stbl, int fd, unsigned int offset, int len)
{
	u_int32_t size;
	u_int32_t type;
	read_hdr(fd, offset, stbl->hdr, "stbl");
	offset += BOX_HLEN;
	len -= BOX_HLEN;
	while (len > 0) {
		seek(fd, offset);
		read_32(fd, &size);
		read_32(fd, &type);
		if (type == *(u_int32_t*)"stts") 
			stts_read(&stbl->stts, fd, offset);
		else if (type == *(u_int32_t*)"ctts")
			ctts_read(&stbl->ctts, fd, offset);
		else if (type == *(u_int32_t*)"stsc")
			stsc_read(&stbl->stsc, fd, offset);
		else if (type == *(u_int32_t*)"stsz")
			stsz_read(&stbl->stsz, fd, offset);
		else if (type == *(u_int32_t*)"stco")
			stco_read(&stbl->stco, fd, offset);
		else if (type == *(u_int32_t*)"stss")
			stss_read(&stbl->stss, fd, offset);
		offset += size;
		len -= size;
	}
	return 1;
}

/*
 * @time is in media timescale 
 * return -1 indicate an error
 */
int stbl_cut(struct stbl *stbl, int fd, unsigned long long time)
{
	unsigned int lencut = 0;
	unsigned long long sample = stts_time_to_sample(&stbl->stts, time);
	unsigned long long keyframe = sample;
	unsigned int chunk_del = 0; /* total chunk need to be deleted */
	unsigned int first_chunk_offset_inc = 0;
	struct stco_entry *e;

	if (stbl->stts.hdr.size == 0 || stbl->stsc.hdr.size == 0 ||
			stbl->stsz.hdr.size == 0 || stbl->stco.hdr.size == 0)
		return -1;
	
	if (stbl->stss.hdr.size != 0)
		keyframe = stss_get_keyframe(&stbl->stss, sample);
	lencut += stsc_cut(fd, &stbl->stsc, keyframe, &stbl->stsz, &first_chunk_offset_inc, &chunk_del);
	lencut += stts_cut(&stbl->stts, keyframe);
	if (stbl->ctts.hdr.size)
		lencut += ctts_cut(&stbl->ctts, keyframe);
	lencut += stsz_cut(&stbl->stsz, keyframe);
	lencut += stco_cut(&stbl->stco, chunk_del);
	if (stbl->stss.hdr.size)
		lencut += stss_cut(&stbl->stss, keyframe);
	/* adjust the first stco_entry offset */
	e = container_of(stbl->stco.entry.next, struct stco_entry, list);
	e->offset += first_chunk_offset_inc; /* is that right? */
	stbl->hdr.size -= lencut;
	return lencut;
}
void stbl_free(struct stbl *stbl)
{
	stsc_free(&stbl->stsc);
	stts_free(&stbl->stts);
	if (stbl->ctts.hdr.size)
		ctts_free(&stbl->ctts);
	stsz_free(&stbl->stsz);
	stco_free(&stbl->stco);
	if (stbl->stss.hdr.size)
		stss_free(&stbl->stss);
}

/* 
 * minf
 */
int minf_read(struct minf *minf, int fd, unsigned int offset, int len)
{
	read_hdr(fd, offset, minf->hdr, "minf");
	offset += BOX_HLEN;
	len -= BOX_HLEN;
	return stbl_read(&minf->stbl, fd, offset, len);
}
/* 
 * @time at media timescale 
 */
int minf_cut(struct minf *minf, int fd, unsigned long long time)
{
	unsigned int lencut = stbl_cut(&minf->stbl, fd, time);
	minf->hdr.size -= lencut;
	return lencut;
}
void minf_free(struct minf *minf)
{
	stbl_free(&minf->stbl);
}

/* 
 * hdlr, has no cut and free
 */
int hdlr_read(struct hdlr *hdlr, int fd, unsigned int offset, int len)
{
	read_fullhdr(fd, offset, hdlr->hdr, "hdlr");
	read_32(fd, &hdlr->pre_define);
	read_32(fd, &hdlr->handler_type);
	
	return 1;
}


/* 
 * mdhd, has no cut and free
 */
int mdhd_read(struct mdhd *mdhd, int fd, unsigned int offset, int len)
{
	read_fullhdr(fd, offset, mdhd->hdr, "mdhd");
	if (mdhd->hdr.ver == 1) {
		read_64(fd, &mdhd->u.l.create_time);
		read_64(fd, &mdhd->u.l.mod_time);
		read_32(fd, &mdhd->u.l.timescale);
		read_64(fd, &mdhd->u.l.duration);
	} else {
		read_32(fd, &mdhd->u.s.create_time);
		read_32(fd, &mdhd->u.s.mod_time);
		read_32(fd, &mdhd->u.s.timescale);
		read_32(fd, &mdhd->u.s.duration);
	}
	
	return 1;
}

/* 
 * mdia 
 */
int mdia_read(struct mdia *mdia, int fd, unsigned int offset, int len)
{
	u_int32_t size;
	u_int32_t type;
	read_hdr(fd, offset, mdia->hdr, "mdia");
	offset += BOX_HLEN;
	len -= BOX_HLEN;
	while (len > 0) {
		seek(fd, offset);
		read_32(fd, &size);
		read_32(fd, &type);
		if (type == *(u_int32_t*)"mdhd") 
			mdhd_read(&mdia->mdhd, fd, offset, size);
		else if (type == *(u_int32_t*)"hdlr")
			hdlr_read(&mdia->hdlr, fd, offset, size);
		else if (type == *(u_int32_t*)"minf")
			minf_read(&mdia->minf, fd, offset, size);
		offset += size;
		len -= size;
	}
	return 1;
}

/*
 * note: time is in second, and must be compute to media timescale
 */
int mdia_cut(struct mdia *mdia, int fd, unsigned int time)
{
	int lencut;
	unsigned long long __time;
	if (mdia->mdhd.hdr.size == 0)
		return 0;
	if (mdia->hdlr.handler_type != *(u_int32_t*)"vide" &&
			mdia->hdlr.handler_type != *(u_int32_t*)"soun")
		return 0;

	if (mdia->mdhd.hdr.ver == 1)
		__time = time * mdia->mdhd.u.l.timescale;
	else __time = time * mdia->mdhd.u.s.timescale;

	lencut = minf_cut(&mdia->minf, fd, __time); 

	/* set duration */
	if (mdia->mdhd.hdr.ver == 1)
		mdia->mdhd.u.l.duration = stts_duration(&mdia->minf.stbl.stts);
	else mdia->mdhd.u.s.duration = stts_duration(&mdia->minf.stbl.stts);

	mdia->hdr.size -= lencut;
	return lencut;
}
/* return value is in second */
unsigned long long mdia_get_duration(struct mdia *mdia)
{
	if (mdia->mdhd.hdr.ver == 1)
		return mdia->mdhd.u.l.duration / mdia->mdhd.u.l.timescale;
	else
		return mdia->mdhd.u.s.duration / mdia->mdhd.u.s.timescale;
}
void mdia_free(struct mdia *mdia)
{
	if (mdia->hdlr.handler_type != *(u_int32_t*)"vide" &&
			mdia->hdlr.handler_type != *(u_int32_t*)"soun")
		return;
	minf_free(&mdia->minf);
}


/* 
 * tkhd, has no cut and free
 */
int tkhd_read(struct tkhd *tkhd, int fd, unsigned int offset, int len)
{
	read_fullhdr(fd, offset, tkhd->hdr, "tkhd");
	if (tkhd->hdr.ver == 1) {
		read_64(fd, &tkhd->u.l.create_time);
		read_64(fd, &tkhd->u.l.mod_time);
		read_32(fd, &tkhd->u.l.track_id);
		read_64(fd, &tkhd->u.l.duration);
	} else {
		read_32(fd, &tkhd->u.s.create_time);
		read_32(fd, &tkhd->u.s.mod_time);
		read_32(fd, &tkhd->u.s.track_id);
		read_32(fd, &tkhd->u.s.duration);
	}
	
	return 1;
}


int trak_read(struct trak *trak, int fd, unsigned int offset, int len)
{
	u_int32_t size;
	u_int32_t type;
	read_hdr(fd, offset, trak->hdr, "trak");
	offset += BOX_HLEN;
	len -= BOX_HLEN;
	while (len > 0) {
		seek(fd, offset);
		read_32(fd, &size);
		read_32(fd, &type);
		if (type == *(u_int32_t*)"tkhd") 
			tkhd_read(&trak->tkhd, fd, offset, size);
		else if (type == *(u_int32_t*)"mdia")
			mdia_read(&trak->mdia, fd, offset, size);
		offset += size;
		len -= size;
	}
	return 1;
}
/*
 * note: time is in second, and must be compute to media timescale
 * note: duration is not update here, will be updated in moov
 * the duration value is only the second
 */
int trak_cut(struct trak *trak, int fd, unsigned int time)
{
	int lencut;
	lencut = mdia_cut(&trak->mdia, fd, time);
	if (trak->tkhd.hdr.ver == 1)
		trak->tkhd.u.l.duration = mdia_get_duration(&trak->mdia);
	else 
		trak->tkhd.u.s.duration = mdia_get_duration(&trak->mdia);
	trak->hdr.size -= lencut;
	return lencut;
}
void trak_free(struct trak *trak)
{
	mdia_free(&trak->mdia);
}


/* 
 * mvhd, has no cut and free
 */
int mvhd_read(struct mvhd *mvhd, int fd, unsigned int offset, int len)
{
	read_fullhdr(fd, offset, mvhd->hdr, "mvhd");
	if (mvhd->hdr.ver == 1) {
		read_64(fd, &mvhd->u.l.create_time);
		read_64(fd, &mvhd->u.l.mod_time);
		read_32(fd, &mvhd->u.l.timescale);
		read_64(fd, &mvhd->u.l.duration);
	} else {
		read_32(fd, &mvhd->u.s.create_time);
		read_32(fd, &mvhd->u.s.mod_time);
		read_32(fd, &mvhd->u.s.timescale);
		read_32(fd, &mvhd->u.s.duration);
	}
	
	return 1;
}

unsigned long long mvhd_get_timescale(struct mvhd *mvhd)
{
	if (mvhd->hdr.ver == 1)
		return mvhd->u.l.duration;
	else return mvhd->u.s.duration;
}
void mvhd_set_duration(struct mvhd *mvhd, unsigned long long duration)
{
	if (mvhd->hdr.ver == 1)
		mvhd->u.l.duration = duration;
	else 
		mvhd->u.s.duration = duration;
}


/* 
 * moov
 */
int moov_read(struct moov *moov, int fd, unsigned int offset, int len)
{
	u_int32_t size;
	u_int32_t type;
	read_hdr(fd, offset, moov->hdr, "moov");
	offset += BOX_HLEN;
	len -= BOX_HLEN;
	INIT_LIST_HEAD(&moov->entry);
	while (len > 0) {
		seek(fd, offset);
		read_32(fd, &size);
		read_32(fd, &type);
		if (type == *(u_int32_t*)"mvhd") 
			mvhd_read(&moov->mvhd, fd, offset, size);
		else if (type == *(u_int32_t*)"trak") {
			struct trak *e;
			MALLOC(e);
			trak_read(e, fd, offset, size);
			list_add_tail(&e->list, &moov->entry);
			moov->count ++;
		}
		offset += size;
		len -= size;
	}
	return 1;
}


/*
 * note: time is in second, and must be compute to media timescale
 */
int moov_cut(struct moov *moov, int fd, unsigned int time, unsigned int *__offset)
{
	int i;
	int lencut = 0;
	unsigned int lowest_offset = 0xFFFFFFFF;
	unsigned int offset;
	unsigned int largest_duration = 0; /* in mvhd timescale */
	struct trak *e = container_of(moov->entry.next, struct trak, list);
	for (i=0; i<moov->count; i++) {
		lencut += trak_cut(e, fd, time);
		if (e->tkhd.hdr.ver == 1) {
			e->tkhd.u.l.duration = e->tkhd.u.l.duration * mvhd_get_timescale(&moov->mvhd);
			if (e->tkhd.u.l.duration > largest_duration)
				largest_duration = e->tkhd.u.l.duration;
		} else  {
			e->tkhd.u.s.duration = e->tkhd.u.s.duration * mvhd_get_timescale(&moov->mvhd);
			if (e->tkhd.u.s.duration > largest_duration)
				largest_duration = e->tkhd.u.s.duration;
		}
		offset = container_of(e->mdia.minf.stbl.stco.entry.next, struct stco_entry, list)->offset;
		if (offset < lowest_offset)
			lowest_offset = offset;
		e = container_of(e->list.next, struct trak, list);
	}
	mvhd_set_duration(&moov->mvhd, largest_duration);
	*__offset = lowest_offset;
	return lencut;
}

void moov_update_offset(struct moov *moov, unsigned int offset)
{
	int i;
	struct trak *e = container_of(moov->entry.next, struct trak, list);
	for (i=0; i<moov->count; i++) {
		if (e->mdia.hdlr.handler_type == *(u_int32_t*)"vide"  ||
				e->mdia.hdlr.handler_type == *(u_int32_t*)"soun") {
			stco_update_offset(&e->mdia.minf.stbl.stco, offset);
		}
		e = container_of(e->list.next, struct trak, list);
	}
}

void moov_free(struct moov *moov)
{
	int i;
	for (i=0; i<moov->count; i++) {
		struct trak *e = container_of(moov->entry.next, struct trak, list);
		trak_free(e);
		list_del(&e->list);
		free(e);
	}
}

int mdat_read(struct mdat *mdat, int fd, unsigned int offset, int len)
{
	read_hdr(fd, offset, mdat->hdr, "mdat");
	return 1;
}

int mdat_cut(struct mdat *mdat, int fd, unsigned int lowest_offset)
{
	int lencut = lowest_offset - (mdat->hdr.offset + BOX_HLEN);
	mdat->lowest_offset = lowest_offset;
	mdat->hdr.size -= lencut;
	return lencut;
}

int mp4_read(struct mp4 *mp4, int fd, unsigned int offset , signed int len)
{
	u_int32_t size;
	u_int32_t type;
	while (len > 0) {
		seek(fd, offset);
		read_32(fd, &size);
		read_32(fd, &type);
		if (type == *(u_int32_t*)"moov") 
			moov_read(&mp4->moov, fd, offset, size);
		else if (type == *(u_int32_t*)"mdat") 
			mdat_read(&mp4->mdat, fd, offset, size);
		offset += size;
		len -= size;
	}
	return 1;
}

int mp4_cut(struct mp4 *mp4, int fd, int time)
{
	unsigned int offset;
	int lencut = 0;
	lencut += moov_cut(&mp4->moov, fd, time, &offset);
	lencut += mdat_cut(&mp4->mdat, fd, offset);

	/* update offset */
	moov_update_offset(&mp4->moov, lencut);
	return lencut;
}
void mp4_free(struct mp4 *mp4)
{
	moov_free(&mp4->moov);
}
